/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package cz.muni.fi.diplomka.servicelayer.gamelogic.resolver;

import cz.fi.muni.diplomka.common.Army;
import cz.fi.muni.diplomka.common.Squad;
import cz.fi.muni.diplomka.common.Unit;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

/**
 * Class used to resolve battle between two Armies
 *
 * @author Jakub Kutil
 */
public class Battler {

    private boolean winnerUnitAttacker;
    private boolean winnerSquadAttacker;
    private Unit winner;
    private Random randomGenerator = new Random();

    /**
     * Fights two Units
     *
     * @param attacker attacking Unit
     * @param defender defending Unit
     * 
     * @return victorious Unit
     */
    public Unit battleUnits(Unit attacker, Unit defender) {
        if (attacker == null) {
            throw new IllegalArgumentException("Attacker cant be null");
        }

        if (defender == null) {
            throw new IllegalArgumentException("Defender cant be null");
        }

        boolean initiative;
        double attackerChanceToHit;
        double defenderChanceToHit;

        attackerChanceToHit = (50 + 2.5 * attacker.getAttack() - 2.5 * defender.getDefense());
        defenderChanceToHit = (50 + 2.5 * defender.getAttack() - 2.5 * attacker.getDefense());

        if (attacker.getInitiative() >= defender.getInitiative()) {
            initiative = true;
        } else {
            initiative = false;
        }

        while (attacker.getHealth() >= 0 && defender.getHealth() >= 0) {
            int randomInt = randomGenerator.nextInt(100);

            if (initiative == true) {

                if (attackerChanceToHit >= randomInt) {

                    int damageDone = randomGenerator.nextInt(attacker.getDamageHigh() - attacker.getDamageLow())
                            + attacker.getDamageLow() - defender.getArmor();
                    defender.lowerHealth(damageDone);

                } else {
                    //     System.out.println("Miss");
                }
                initiative = false;
            } else {
                if (defenderChanceToHit >= randomInt) {


                    int damageDone = randomGenerator.nextInt(defender.getDamageHigh() - defender.getDamageLow())
                            + defender.getDamageLow() - attacker.getArmor();
                    attacker.lowerHealth(damageDone);
                    // System.out.println("Hit - roll: " + randomInt + "chance: " + attackerChanceToHit + "damage: " + damageDone);

                } else {
                    //  System.out.println("Miss");
                }
                initiative = true;
            }

        }
        if (attacker.getHealth() > 0) {
            winnerUnitAttacker = true;
            return attacker;
        }
        winnerUnitAttacker = false;
        return defender;
    }

    /**
     * Battles two Squads
     *
     * @param attackingSquad attacking Squad
     * @param defendingSquad defending Squad
     * 
     * @return victorious Squad
     */
    public Squad battleSquads(Squad attackingSquad, Squad defendingSquad) {

        if (attackingSquad == null) {
            throw new IllegalArgumentException("Attacking squad cant be null");
        }

        if (defendingSquad == null) {
            throw new IllegalArgumentException("Defending squad cant be null");
        }

        int attackerMaxHealth = attackingSquad.getUnit().getHealth();
        int defenderMaxHealth = defendingSquad.getUnit().getHealth();



        winner = this.battleUnits(attackingSquad.getUnit(), defendingSquad.getUnit());

        while (attackingSquad.isActive() && defendingSquad.isActive()) {

            if (isWinnerUnitAttacker() == true) {
                defendingSquad.getUnit().setHealth(defenderMaxHealth);
                defendingSquad.lowerCount();
                defendingSquad.raiseLostCount();

                if (defendingSquad.isSquadBroken()) {
                    defendingSquad.setActive(false);
                    System.out.println("Winner att" + attackingSquad.toString());
                    System.out.println("Looser deff" + defendingSquad.toString());
                    return null;
                } else {
                    winner = this.battleUnits(winner, defendingSquad.getUnit());
                }
            } else {
                attackingSquad.getUnit().setHealth(attackerMaxHealth);
                attackingSquad.lowerCount();
                attackingSquad.raiseLostCount();

                if (attackingSquad.isSquadBroken()) {
                    attackingSquad.setActive(false);
                    System.out.println("Looser att" + attackingSquad.toString());
                    System.out.println("Winner deff" + defendingSquad.toString());
                    return null;
                } else {
                    winner = this.battleUnits(attackingSquad.getUnit(), winner);
                }
            }
        }
        return null;
    }

    /**
     * Battles two Armies
     *
     * @param attackingArmy attacking Army
     * @param defendingArmy defending Army
     * 
     * @return both Armies after battle
     */
    public Map<String,Army> battleArmies(Army attackingArmy, Army defendingArmy) {
        if (attackingArmy == null) {
            throw new IllegalArgumentException("Attacking army cant be null");
        }

        if (defendingArmy == null) {
            throw new IllegalArgumentException("Defending army cant be null");
        }


        for (int i = 1; i <= attackingArmy.getSquads().size(); i++) {

            if (attackingArmy.getSquadAtPosition(i).isActive()) {
                for (int j = 1; j <= defendingArmy.getSquads().size(); j++) {

                    if (defendingArmy.getSquadAtPosition(j).isActive()) {
                        this.battleSquads(attackingArmy.getSquadAtPosition(i), defendingArmy.getSquadAtPosition(j));
                    }
                }
            }
        }
        Map<String,Army> armies = new HashMap<>();
        armies.put("attacker", attackingArmy);
        armies.put("defender", defendingArmy);
        return armies;
    }

    public boolean isWinnerUnitAttacker() {
        return winnerUnitAttacker;
    }

    public boolean isWinnerSquadAttacker() {
        return winnerSquadAttacker;
    }
}
